//
//  vdRTTarget.mm
//  Void Dead
//
//  Created by Sidney Just on 23.03.10.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import "vdRTTarget.h"


@implementation vdRTTarget
@synthesize texture;

- (BOOL)renderNode:(vdNode *)node withOffset:(CGPoint)offset {
	if(!bound)
		return NO;
	
	vdKernel	*father = node.father;
	vdView		*mother = node.mother;
	node.father = [vdKernel sharedKernel];
	node.mother = [vdKernel sharedKernel].renderView;
	
	[node contact:offset :[vdKernel sharedKernel].deltaTime];
	
	node.father = father;
	node.mother = mother;
	
	return YES;
}

- (void)clear:(vdColor *)color {
	if(!bound)
		return;
	
	glClearColor(color->red, color->green, color->blue, color->alpha);
	glClear(GL_COLOR_BUFFER_BIT);
}

- (void)bind {
	if(bound)
		return;
	
	[[vdRenderer sharedRenderer] flushContent];
	
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
	{
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastFramebuffer);		
		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
	} else {
		glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &lastFramebuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
		glPushMatrix();
	}
#else
	glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &lastFramebuffer);
	glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
	glPushMatrix();
#endif
	bound = YES;
}

- (void)unbind {
	if(!bound)
		return;
	
	[[vdRenderer sharedRenderer] flushContent];
	
	if([vdKernel sharedKernel].renderView.viewFramebuffer == lastFramebuffer)
	{
		[[vdKernel sharedKernel].renderView bindFramebuffer];
	} else {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, lastFramebuffer);
		} else {
			glBindFramebufferOES(GL_FRAMEBUFFER_OES, lastFramebuffer);
			glPopMatrix();
		}
#else
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, lastFramebuffer);
		glPopMatrix();
#endif
	}
	
	bound = NO;
}

- (BOOL)createFramebuffer:(CGRect)rect {
	int dimension_x = (int)(rect.size.width  - rect.origin.x);
	int dimension_y = (int)(rect.size.height - rect.origin.y);
	
	if(!((dimension_x != 0) && !(dimension_x & (dimension_x - 1))))
	{
		if(!((dimension_y != 0) && !(dimension_y & (dimension_y - 1))))
		{
			return NO;
		}
	}
	
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
	{
		glGetIntegerv(GL_FRAMEBUFFER_BINDING, &lastFramebuffer);
		
		glGenFramebuffers(1, &framebuffer);
		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
	} else {
		glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &lastFramebuffer);
		
		glGenFramebuffersOES(1, &framebuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
	}
#else
	glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &lastFramebuffer);
	
	glGenFramebuffersOES(1, &framebuffer);
	glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
#endif
	
	glGenTextures(1, &texHandle);
	glBindTexture(GL_TEXTURE_2D, texHandle);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  dimension_x, dimension_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	
	texture = [[vdTexNode alloc] initWithHandle:texHandle andSize:CGRectMake(0, 0, dimension_x, dimension_y)];
	
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
	{
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.texture, 0);
	} else {
		glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, texture.texture, 0);
	}
#else
	glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, texture.texture, 0);
#endif
	
	if([vdKernel sharedKernel].renderView.viewFramebuffer == lastFramebuffer)
	{
		[[vdKernel sharedKernel].renderView bindFramebuffer];
	} else {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, lastFramebuffer);
		} else {
			glBindFramebufferOES(GL_FRAMEBUFFER_OES, lastFramebuffer);
		}
#else
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, lastFramebuffer);
#endif
	}
	
	bound = NO;
	return YES;
}

- (id)initWithSize:(CGRect)rect {
	if(self = [super init])
	{
		if(![self createFramebuffer:rect])
		{
			vdLog(@"Failed to create RTTarget with non power of two size!");
			
			[self release];
			return NULL;
		}
			
		vdLog(@"Created RTTarget %@", self);
	}
	return self;
}

- (id)init {
	if(self = [super init])
	{
		int dimension = 512;
		if([vdKernel sharedKernel].renderView.backingWidth > 480)
		{
			dimension = 1024;
		}
		
		CGRect rect = CGRectMake(0, 0, dimension, dimension);
		[self createFramebuffer:rect];
		
		vdLog(@"Created RTTarget %@", self);
	}
	return self;
}

- (void)dealloc {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if([vdKernel sharedKernel].rAPI == OpenGLESAPI2)
	{
		glDeleteFramebuffers(1, &framebuffer);
		glDeleteTextures(1, &texHandle);
	} else {
		glDeleteFramebuffersOES(1, &framebuffer);
		glDeleteTextures(1, &texHandle);
	}
#else
	glDeleteFramebuffersOES(1, &framebuffer);
	glDeleteTextures(1, &texHandle);
#endif
	
	[texture release];
	
	vdLog(@"Deleted RTTarget @", self);
					 
	[super dealloc];
}

@end
